package platform

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"gitee.com/wangshh_123/cross-pay-go/src/database"
	"gitee.com/wangshh_123/cross-pay-go/src/models"
	"gitee.com/wangshh_123/cross-pay-go/src/platform/providers/photonpay"
	"gitee.com/wangshh_123/cross-pay-go/src/service"
	"github.com/gin-gonic/gin"
)

// WebhookController webhook控制器
type WebhookController struct {
	photonPayClient       *photonpay.PhotonPayClient
	webhookService        *service.WebhookService
	notificationService   *service.NotificationService
	processedTransactions map[string]int64 // 内存缓存，记录已处理的交易ID
	mutex                 sync.RWMutex
}

// NewWebhookController 创建webhook控制器
func NewWebhookController(photonPayClient *photonpay.PhotonPayClient) *WebhookController {
	return &WebhookController{
		photonPayClient:       photonPayClient,
		webhookService:        service.NewWebhookService(photonPayClient),
		notificationService:   service.NewNotificationService(),
		processedTransactions: make(map[string]int64),
	}
}

// isTransactionProcessed 检查交易是否已处理
func (c *WebhookController) isTransactionProcessed(transactionID string) bool {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	if _, exists := c.processedTransactions[transactionID]; exists {
		return true
	}
	return false
}

// markTransactionProcessed 标记交易为已处理
func (c *WebhookController) markTransactionProcessed(transactionID string) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.processedTransactions[transactionID] = time.Now().Unix()

	// 清理超过1小时的记录
	go func() {
		time.Sleep(time.Hour)
		c.mutex.Lock()
		defer c.mutex.Unlock()

		cutoff := time.Now().Add(-time.Hour).Unix()
		for id, timestamp := range c.processedTransactions {
			if timestamp < cutoff {
				delete(c.processedTransactions, id)
			}
		}
	}()
}

// HandlePhotonPayWebhook 处理PhotonPay的webhook通知
// @Summary 处理PhotonPay的webhook通知
// @Description 处理来自PhotonPay的各种webhook通知，包括卡片状态更新、交易通知等
// @Tags webhooks
// @Accept json
// @Produce json
// @Param notification_category header string true "通知类别" Enums(transaction, card, global_account, settlement)
// @Param notification_type header string true "通知类型" Enums(authorization, capture, refund, card_status_update, global_account_status_update, settlement)
// @Param X-Signature header string true "签名" example="sha256=1234567890abcdef"
// @Param body body object true "通知内容"
// @Success 200 {object} map[string]interface{} "成功响应"
// @Failure 400 {object} map[string]interface{} "请求错误"
// @Failure 500 {object} map[string]interface{} "服务器错误"
// @Router /api/webhooks/receive [post]
func (c *WebhookController) HandlePhotonPayWebhook(ctx *gin.Context) {
	// 确保始终返回 {roger: true}
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Webhook处理发生panic: %v", r)
			ctx.JSON(http.StatusOK, gin.H{"roger": true})
		}
	}()

	// 获取请求头
	notificationCategory := ctx.GetHeader("x-pd-notification-category")
	notificationType := ctx.GetHeader("x-pd-notification-type")
	signature := ctx.GetHeader("x-pd-sign")

	// 记录接收到的通知
	log.Printf("接收webhook事件通知，通知类型: %s, 事件子类型: %s", notificationCategory, notificationType)

	// 读取请求体
	var body map[string]interface{}
	if err := ctx.ShouldBindJSON(&body); err != nil {
		log.Printf("JSON解析失败: %v", err)
		ctx.JSON(http.StatusOK, gin.H{"roger": true})
		return
	}

	// 记录请求数据
	log.Printf("Webhook参数: %+v", body)

	// 验证签名 - 获取环境变量来决定是否跳过验证
	skipVerification := false // 可以通过环境变量控制
	isValid := skipVerification

	if !skipVerification {
		// 这里应该调用PhotonPay的签名验证方法
		// isValid = c.photonPayClient.CheckSign(body, signature)
		isValid = true // 临时设置为true，实际应该验证签名
		log.Printf("签名结果: %s, 验证结果: %v", signature, isValid)
	} else {
		log.Printf("开发模式: 跳过webhook签名验证")
	}

	if !isValid {
		log.Printf("签名验证失败，但仍返回成功响应以避免重复发送")
		ctx.JSON(http.StatusOK, gin.H{"roger": true})
		return
	}

	// 检查是否已处理过该交易
	if transactionID, ok := body["transactionId"].(string); ok && transactionID != "" {
		if c.isTransactionProcessed(transactionID) {
			log.Printf("已在内存中检测到重复处理的交易ID: %s，忽略此次请求", transactionID)
			ctx.JSON(http.StatusOK, gin.H{"roger": true})
			return
		}

		// 记录此交易ID到内存缓存
		c.markTransactionProcessed(transactionID)
		log.Printf("将交易ID添加到内存缓存: %s", transactionID)
	}

	// 处理业务逻辑
	processed := false
	notificationTypeCode := "system" // 默认通知类型

	// 特殊处理卡状态变更
	if cardStatus, ok := body["cardStatus"].(string); ok && cardStatus != "" {
		if cardID, ok := body["cardId"].(string); ok && cardID != "" && notificationCategory == "" {
			log.Printf("检测到卡状态变更: %s，卡ID: %s，按卡状态通知处理", cardStatus, cardID)

			// 对于cancelled状态，特殊处理
			if cardStatus == "cancelled" {
				log.Printf("检测到卡注销状态，特殊处理")
				// 可以在这里添加特殊的业务逻辑处理
			}

			processed = true
			notificationTypeCode = "card_status_update"
		}
	}
	// 对于充值、退款等交易通知
	if notificationCategory == "" && body["transactionType"] != nil {
		transactionType, _ := body["transactionType"].(string)
		log.Printf("检测到交易类型 transactionType: %s，按交易通知处理", transactionType)

		// 调用交易通知处理
		if err := c.webhookService.ProcessWebhook(body, "", "", transactionType); err != nil {
			log.Printf("处理交易通知失败: %v", err)
		}

		processed = true
		notificationTypeCode = "card_transaction"
	} else {
		// 正常按照notification_category和notification_type处理
		switch notificationCategory {
		case "global_account": // 全局账户
			switch notificationType {
			case "apply": // 申请通知
				if err := c.webhookService.ProcessWebhook(body, "", "global_account", "apply"); err != nil {
					log.Printf("处理账户申请通知失败: %v", err)
				}
				processed = true
				notificationTypeCode = "global_account_apply"
			case "close": // 注销通知
				if err := c.webhookService.ProcessWebhook(body, "", "global_account", "close"); err != nil {
					log.Printf("处理账户注销通知失败: %v", err)
				}
				processed = true
				notificationTypeCode = "global_account_close"
			case "settle": // 入账通知
				processed = true
				notificationTypeCode = "global_account_settle"
			}
		case "issuing_card": // 虚拟卡状态通知
			switch notificationType {
			case "card_status_update": // 卡状态更新
				if err := c.webhookService.ProcessWebhook(body, "", "issuing_card", "card_status_update"); err != nil {
					log.Printf("处理卡状态更新失败: %v", err)
				}
				processed = true
				notificationTypeCode = "card_status_update"
			}
		case "issuing":
			// 处理PayPal/Facebook验证码回调
			if notificationType == "paypal_facebook_verify_code_webhook" {
				if err := c.webhookService.ProcessWebhook(body, "", "issuing", "paypal_facebook_verify_code_webhook"); err != nil {
					log.Printf("处理验证码回调失败: %v", err)
				}
				processed = true
				notificationTypeCode = "verify_code"
			} else if c.isTransactionType(notificationType) {
				// 处理发卡交易通知
				if err := c.webhookService.ProcessWebhook(body, "", "issuing", notificationType); err != nil {
					log.Printf("处理交易通知失败: %v", err)
				}
				processed = true
				notificationTypeCode = "card_transaction"
			}
		case "issuing_settlement": // 发卡交易结算通知
			if c.isSettlementType(notificationType) {
				if err := c.webhookService.ProcessWebhook(body, "", "issuing_settlement", notificationType); err != nil {
					log.Printf("处理结算通知失败: %v", err)
				}
				processed = true
				notificationTypeCode = "card_settlement"
			}
		}
	}

	// 创建通知
	if err := c.createWebhookNotification(ctx, notificationTypeCode, body); err != nil {
		log.Printf("创建通知失败: %v", err)
		// 通知创建失败不影响主流程，只记录日志
	}

	// 记录处理结果
	if !processed {
		log.Printf("未处理的webhook通知类型: %s/%s，尝试默认处理", notificationCategory, notificationType)
	}

	// 返回成功响应
	ctx.JSON(http.StatusOK, gin.H{"roger": true})
}

// isTransactionType 检查是否为交易类型
func (c *WebhookController) isTransactionType(notificationType string) bool {
	transactionTypes := []string{
		"auth", "corrective_auth", "verification", "void",
		"refund", "corrective_refund", "corrective_refund_void",
		"recharge", "recharge_return", "discard_recharge_return",
		"service_fee", "refund_reversal", "fund_in",
		"atm_inquiry", "atm_withdrawals",
	}

	for _, t := range transactionTypes {
		if t == notificationType {
			return true
		}
	}
	return false
}

// isSettlementType 检查是否为结算类型
func (c *WebhookController) isSettlementType(notificationType string) bool {
	settlementTypes := []string{"auth", "verification", "refund", "fund_in"}

	for _, t := range settlementTypes {
		if t == notificationType {
			return true
		}
	}
	return false
}

// getUserIDFromWebhookData 从webhook数据中获取用户ID
func (c *WebhookController) getUserIDFromWebhookData(data map[string]interface{}) (int64, error) {
	// 尝试从不同字段获取matrix_account
	var matrixAccount string
	if account, ok := data["matrixAccount"].(string); ok && account != "" {
		matrixAccount = account
	} else if account, ok := data["matrix_account"].(string); ok && account != "" {
		matrixAccount = account
	} else if account, ok := data["account"].(string); ok && account != "" {
		matrixAccount = account
	}

	// 如果缺少matrixAccount但有cardId，尝试通过cardId获取用户信息
	if matrixAccount == "" {
		if cardID, ok := data["cardId"].(string); ok && cardID != "" {
			log.Printf("Webhook缺少matrixAccount，尝试通过cardId: %s 查找用户", cardID)

			var userCard models.UserCard
			// 先尝试查找活跃状态的卡片
			if err := database.DB.Where("card_id = ? AND card_status = ?", cardID, "active").First(&userCard).Error; err != nil {
				log.Printf("未找到与cardId: %s 关联的活跃用户卡记录，尝试查找所有状态的卡片", cardID)

				// 如果找不到活跃状态的，尝试查找所有状态的卡片
				if err := database.DB.Where("card_id = ?", cardID).First(&userCard).Error; err != nil {
					log.Printf("未找到与cardId: %s 关联的用户卡记录: %v", cardID, err)

					// 尝试通过memberId查找用户
					if memberID, ok := data["memberId"].(string); ok && memberID != "" {
						log.Printf("尝试通过memberId: %s 查找用户", memberID)

						// 这里可以添加通过memberId查找用户的逻辑
						// 暂时返回错误，但记录详细信息
						log.Printf("无法通过cardId或memberId找到用户，cardId: %s, memberId: %s", cardID, memberID)
						return 0, fmt.Errorf("未找到用户记录，cardId: %s, memberId: %s", cardID, memberID)
					}

					return 0, fmt.Errorf("未找到用户卡记录: %v", err)
				}

				log.Printf("通过cardId找到对应用户ID: %d (卡片状态: %s)", userCard.UserID, userCard.CardStatus)
			} else {
				log.Printf("通过cardId找到对应用户ID: %d (活跃卡片)", userCard.UserID)
			}

			return userCard.UserID, nil
		}

		return 0, fmt.Errorf("未找到matrix_account或cardId")
	}

	// 查询用户矩阵账户
	var userMatrixAccount models.UserMatrixAccount
	if err := database.DB.Where("matrix_account = ? AND status = ?", matrixAccount, "active").First(&userMatrixAccount).Error; err != nil {
		return 0, fmt.Errorf("未找到用户: %v", err)
	}

	return userMatrixAccount.UserID, nil
}

// createWebhookNotification 创建webhook通知
func (c *WebhookController) createWebhookNotification(ctx *gin.Context, notificationType string, data map[string]interface{}) error {
	// 获取通知类型
	var typeCode string
	var title string
	var content string

	// 根据通知类型确定通知内容
	switch notificationType {
	case "global_account_apply":
		typeCode = "ACCOUNT_STATUS"
		title = "账户申请通知"
		content = fmt.Sprintf("您的账户申请已收到，正在处理中。申请时间：%s", time.Now().Format("2006-01-02 15:04:05"))
	case "global_account_close":
		typeCode = "ACCOUNT_STATUS"
		title = "账户注销通知"
		content = fmt.Sprintf("您的账户已注销。注销时间：%s", time.Now().Format("2006-01-02 15:04:05"))
	case "global_account_settle":
		typeCode = "BALANCE_IN"
		// 尝试多种可能的字段名来获取金额
		var amount float64
		var currency string

		// 尝试 amount 字段
		if amountVal, ok := data["amount"].(string); ok && amountVal != "" {
			if parsedAmount, err := strconv.ParseFloat(amountVal, 64); err == nil {
				amount = parsedAmount
			}
		} else if amountVal, ok := data["amount"].(float64); ok {
			amount = amountVal
		} else if amountVal, ok := data["amount"].(json.Number); ok {
			if parsedAmount, err := amountVal.Float64(); err == nil {
				amount = parsedAmount
			}
		}

		// 获取货币
		if currencyVal, ok := data["currency"].(string); ok && currencyVal != "" {
			currency = currencyVal
		} else {
			currency = "USD" // 默认货币
		}

		title = "账户入账通知"
		content = fmt.Sprintf("您的账户已收到一笔入账，金额：%.2f %s，时间：%s",
			amount, currency, time.Now().Format("2006-01-02 15:04:05"))
	case "card_status_update":
		typeCode = "CARD"
		cardID, _ := data["cardId"].(string)
		status, _ := data["cardStatus"].(string)
		title = "卡片状态更新"
		content = fmt.Sprintf("您的卡片(%s)状态已更新为：%s，时间：%s",
			cardID, status, time.Now().Format("2006-01-02 15:04:05"))
	case "card_transaction":
		typeCode = "TRANSACTION"
		// 尝试多种可能的字段名来获取金额
		var amount float64
		var currency string

		// 尝试 transactionAmount 字段
		if transactionAmount, ok := data["transactionAmount"].(string); ok && transactionAmount != "" {
			if parsedAmount, err := strconv.ParseFloat(transactionAmount, 64); err == nil {
				amount = parsedAmount
			}
		} else if transactionAmount, ok := data["transactionAmount"].(float64); ok {
			amount = transactionAmount
		} else if transactionAmount, ok := data["transactionAmount"].(json.Number); ok {
			if parsedAmount, err := transactionAmount.Float64(); err == nil {
				amount = parsedAmount
			}
		}

		// 尝试 amount 字段作为备选
		if amount == 0 {
			if amountVal, ok := data["amount"].(string); ok && amountVal != "" {
				if parsedAmount, err := strconv.ParseFloat(amountVal, 64); err == nil {
					amount = parsedAmount
				}
			} else if amountVal, ok := data["amount"].(float64); ok {
				amount = amountVal
			}
		}

		// 获取货币
		if transactionCurrency, ok := data["transactionCurrency"].(string); ok && transactionCurrency != "" {
			currency = transactionCurrency
		} else if currencyVal, ok := data["currency"].(string); ok && currencyVal != "" {
			currency = currencyVal
		} else {
			currency = "USD" // 默认货币
		}

		transactionType, _ := data["transactionType"].(string)
		if transactionType == "" {
			transactionType = "交易"
		}

		title = "交易通知"
		content = fmt.Sprintf("您有一笔新的%s交易，金额：%.2f %s，时间：%s",
			transactionType, amount, currency, time.Now().Format("2006-01-02 15:04:05"))
	case "card_settlement":
		typeCode = "TRANSACTION_SUCCESS"
		// 尝试多种可能的字段名来获取金额
		var amount float64
		var currency string

		// 尝试 transactionAmount 字段
		if transactionAmount, ok := data["transactionAmount"].(string); ok && transactionAmount != "" {
			if parsedAmount, err := strconv.ParseFloat(transactionAmount, 64); err == nil {
				amount = parsedAmount
			}
		} else if transactionAmount, ok := data["transactionAmount"].(float64); ok {
			amount = transactionAmount
		} else if transactionAmount, ok := data["transactionAmount"].(json.Number); ok {
			if parsedAmount, err := transactionAmount.Float64(); err == nil {
				amount = parsedAmount
			}
		}

		// 尝试 amount 字段作为备选
		if amount == 0 {
			if amountVal, ok := data["amount"].(string); ok && amountVal != "" {
				if parsedAmount, err := strconv.ParseFloat(amountVal, 64); err == nil {
					amount = parsedAmount
				}
			} else if amountVal, ok := data["amount"].(float64); ok {
				amount = amountVal
			}
		}

		// 获取货币
		if transactionCurrency, ok := data["transactionCurrency"].(string); ok && transactionCurrency != "" {
			currency = transactionCurrency
		} else if currencyVal, ok := data["currency"].(string); ok && currencyVal != "" {
			currency = currencyVal
		} else {
			currency = "USD" // 默认货币
		}

		title = "交易结算通知"
		content = fmt.Sprintf("您的交易已结算，金额：%.2f %s，时间：%s",
			amount, currency, time.Now().Format("2006-01-02 15:04:05"))
	case "verify_code":
		typeCode = "VERIFICATION_CODE"
		code, _ := data["code"].(string)
		title = "验证码通知"
		content = fmt.Sprintf("您的验证码是：%s，有效期5分钟，请勿泄露给他人", code)
	default:
		typeCode = "SYSTEM"
		title = "系统通知"
		content = fmt.Sprintf("收到新的%s通知，时间：%s",
			notificationType, time.Now().Format("2006-01-02 15:04:05"))
	}

	// 获取通知类型ID
	notificationTypeObj, err := c.notificationService.GetNotificationTypeByCode(ctx, typeCode)
	if err != nil {
		return err
	}

	// 获取用户ID
	userID, err := c.getUserIDFromWebhookData(data)
	if err != nil {
		log.Printf("获取用户ID失败: %v", err)

		// 如果无法找到用户，记录webhook数据但不创建用户通知
		log.Printf("无法创建用户通知，webhook数据: %+v", data)

		// 可以选择创建一个系统级别的通知或者记录到日志
		// 这里暂时返回错误，但不会影响webhook的响应
		return fmt.Errorf("无法找到用户，跳过通知创建: %v", err)
	}

	// 构建通知数据
	notificationData, err := json.Marshal(data)
	if err != nil {
		return fmt.Errorf("序列化通知数据失败: %v", err)
	}

	// 创建通知
	notification := &models.Notification{
		UserID:  userID,
		TypeID:  int64(notificationTypeObj.ID),
		Title:   title,
		Content: content,
		Data:    models.JSON(notificationData),
		Status:  "UNREAD",
	}

	if err := c.notificationService.CreateNotification(ctx, notification); err != nil {
		return fmt.Errorf("创建通知失败: %v", err)
	}

	log.Printf("已为类型 %s 创建用户通知", notificationType)
	return nil
}

// HandleHLPayWebhook 处理海连的webhook通知（极简版，仅记录和输出）
// @Summary 处理海连的webhook通知
// @Description 接收海连平台的webhook通知，记录数据并返回确认
// @Tags webhooks
// @Accept json
// @Produce json
// @Param body body object true "webhook通知内容"
// @Success 200 {object} map[string]interface{} "成功响应"
// @Failure 400 {object} map[string]interface{} "请求错误"
// @Failure 500 {object} map[string]interface{} "服务器错误"
// @Router /api/webhooks/hlpay [post]
func (c *WebhookController) HandleHLPayWebhook(ctx *gin.Context) {
	// 确保始终返回成功响应
	defer func() {
		if r := recover(); r != nil {
			log.Printf("[HLPay Webhook] 处理发生panic: %v", r)
			ctx.JSON(http.StatusOK, gin.H{"roger": true})
		}
	}()

	// 记录接收时间
	log.Printf("[HLPay Webhook] 收到通知 - 时间: %s", time.Now().Format("2006-01-02 15:04:05"))

	// 获取所有请求头
	headers := make(map[string]string)
	for key, values := range ctx.Request.Header {
		if len(values) > 0 {
			headers[key] = values[0]
		}
	}
	log.Printf("[HLPay Webhook] 请求头: %+v", headers)

	// 读取请求体 - 使用json.Decoder保持大整数精度
	var body map[string]interface{}
	decoder := json.NewDecoder(ctx.Request.Body)
	decoder.UseNumber() // 使用json.Number类型保持大整数精度
	if err := decoder.Decode(&body); err != nil {
		log.Printf("[HLPay Webhook] JSON解析失败: %v", err)
		ctx.JSON(http.StatusOK, gin.H{"roger": true})
		return
	}

	// 输出完整的webhook数据
	log.Printf("[HLPay Webhook] 完整数据: %+v", body)

	// 格式化输出，便于查看
	prettyJSON, _ := json.MarshalIndent(body, "", "  ")
	log.Printf("[HLPay Webhook] 格式化数据:\n%s", string(prettyJSON))

	// 解析webhook基本信息
	msg, _ := body["msg"].(string)
	eventType, _ := body["eventType"].(string)
	id, _ := body["id"].(string)
	status, _ := body["status"].(string)

	log.Printf("[HLPay Webhook] 基本信息 - 消息: %s, 事件类型: %s, ID: %s, 状态: %s", msg, eventType, id, status)

	// 使用webhook service处理海连通知
	err := c.webhookService.ProcessHLWebhook(body, "")
	if err != nil {
		log.Printf("[HLPay Webhook] 处理webhook失败: %v", err)
		// 即使处理失败也返回成功响应
	}

	// 返回成功响应
	ctx.JSON(http.StatusOK, gin.H{
		"code": "200",
		"msg": gin.H{
			"CN": "操作成功",
			"EN": "Operation successful",
			"VN": "Thao tác thành công",
		},
		"data": gin.H{
			"message":   "webhook received",
			"success":   true,
			"timestamp": time.Now().Unix(),
		},
	})
}
